package nba2kmodtool.filedesc;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import javax.media.j3d.AmbientLight;
import javax.media.j3d.Appearance;
import javax.media.j3d.BoundingSphere;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.DirectionalLight;
import javax.media.j3d.Material;
import javax.media.j3d.Shape3D;
import javax.media.j3d.Texture;
import javax.media.j3d.TextureAttributes;
import javax.vecmath.Color3f;
import javax.vecmath.Color4f;
import javax.vecmath.Point3d;
import javax.vecmath.Point3f;
import javax.vecmath.TexCoord2f;
import javax.vecmath.Vector3f;

import nba2kmodtool.util.BufferUtil;
import nba2kmodtool.util.ByteFileReader;

import com.sun.j3d.loaders.IncorrectFormatException;
import com.sun.j3d.loaders.ParsingErrorException;
import com.sun.j3d.loaders.objectfile.ObjectFile;
import com.sun.j3d.utils.geometry.GeometryInfo;
import com.sun.j3d.utils.geometry.NormalGenerator;
import com.sun.j3d.utils.image.TextureLoader;

/**
 * NBA2K Game Model Loader
 * @company ZSword (C) Copyright
 * @author JemiZhuu(周士淳)
 * @category N2kModelLoader
 * @version 1.0
 * @since 2011-11-16
 */
@SuppressWarnings("unchecked")
public class N2kModelLoader extends ObjectFile {

	private float radians;
	// First, lists of points are read from the .obj file into these arrays. . .
	private ArrayList<Point3f> coordList; // Holds Point3f
	private ArrayList<TexCoord2f> texList; // Holds TexCoord2f
	private ArrayList<Vector3f> normList; // Holds Vector3f
	// . . . and index lists are read into these arrays.
	private ArrayList<Integer> coordIdxList; // Holds Integer index into coordList
	private ArrayList<Integer> texIdxList; // Holds Integer index into texList
	private ArrayList<Integer> normIdxList; // Holds Integer index into normList
	// value=String name of group
	private String curSgroup;
	// . . . and Smoothing Group info is converted into these.
	private HashMap<String, ArrayList<String>> triSgroups; // key=String name of group
	private ArrayList<List<?>> parts;
	// Finally, coordList, texList, and normList are converted to arrays for
	// use with GeometryInfo
	private Point3f coordArray[] = null;
	private Vector3f normalArray[] = null;
	private TexCoord2f textureArray[] = null;
	private ObjectFileMaterials materials = null;
	private IntBuffer faceBuff = null;
	private Appearance appearance = null;

	/**
	 * The Object File is loaded from the already opened file.
	 * To attach the model to your scene, call getSceneGroup() on
	 * the Scene object passed back, and attach the returned
	 * BranchGroup to your scene graph.  For an example, see
	 * j3d-examples/ObjLoad/ObjLoad.java.
	 * @throws IOException
	 */
	public BranchGroup load(BaseIffFile iff, N2k3DModelPart[] models, Appearance appearance)
			throws IncorrectFormatException, ParsingErrorException, IOException {
		coordList = new ArrayList<Point3f>();
		texList = new ArrayList<TexCoord2f>();
		normList = new ArrayList<Vector3f>();
		coordIdxList = new ArrayList<Integer>();
		texIdxList = new ArrayList<Integer>();
		normIdxList = new ArrayList<Integer>();
		curSgroup = null;
		this.appearance = appearance;
		materials = new ObjectFileMaterials();
		Material material = new Material();
		parts = new ArrayList();
		loadIffModel(iff, models);
		resize();
		return createScene();
	}

	/**
	 * @param textpic
	 * @throws IOException
	 */
	private void createTextureAppearance(BufferedImage... textpic) {
		//def colors
		Color3f black = new Color3f(0.0f, 0.0f, 0.0f);
		Color3f white = new Color3f(1.0f, 1.0f, 1.0f);
		Color3f red = new Color3f(0.7f, 0.7f, 0.7f);
		Appearance ap = new Appearance();
		if (textpic.length > 0 && textpic[0] != null) {
			// create texture
			TextureLoader loader = new TextureLoader(textpic[0]);
			Texture texture = loader.getTexture();//创建纹理对象
			texture.setBoundaryModeS(Texture.WRAP);
			texture.setBoundaryModeT(Texture.WRAP);
			texture.setBoundaryColor(new Color4f(0.0f, 1.0f, 0.0f, 0.0f));
			//create appearance
			TextureAttributes textAttr = new TextureAttributes();
			textAttr.setTextureMode(TextureAttributes.MODULATE);
			ap.setTexture(texture);
			ap.setTextureAttributes(textAttr);
		}
		//set material
		ap.setMaterial(new Material(red, red, black, black, 50.0f));
		this.appearance = ap;
	}

	private void createSimpleAppearance() {
		Material m = new Material();
		Appearance a = new Appearance();
		a.setMaterial(m);
		this.appearance = a;
	}

	private void loadIffModel(BaseIffFile iff, N2k3DModelPart[] models) throws IOException {
		ByteFileReader io = new ByteFileReader(iff.getFile(), "r");
		for (int part = 0; part < models.length; part++) {
			N2k3DModelPart model = models[part];
			List<FloatBuffer> vertexts = iff.getChildModelVertets(model, io);
			List<IntBuffer> faces = iff.getChildModelFaces(model, io);
			for (int p = 0; p < model.getChildNum(); p++) {
				FloatBuffer tvList = vertexts.get(p * 2);
				FloatBuffer uvnList = vertexts.get(p * 2 + 1);
				List tempCoordList = new ArrayList();
				List tempCoordIdxList = new ArrayList();
				List tempNormList = new ArrayList();
				List tempNormIdxList = new ArrayList();
				List tempTexList = new ArrayList();
				List tempTexIdxList = new ArrayList();
				int vertexNum = tvList.capacity() / 3;
				int perSize = model.getPerVertexSize();
				//		vertexBuff = FloatBuffer.allocate(3 * vertexNum);
				//		normalBuff = FloatBuffer.allocate(3 * vertexNum);
				//		uvBuff = FloatBuffer.allocate(2 * vertexNum);
				//System.out.println(buffer.capacity());
				for (int i = 0; i < vertexNum; i++) {
					Point3f vertex = new Point3f();
					float x = tvList.get();
					float y = tvList.get();
					float z = tvList.get();
					vertex.x = x;
					vertex.y = y;
					vertex.z = z;
					tempCoordList.add(vertex);
					this.coordList.add(vertex);
					//			vertexBuff.put(x);
					//			vertexBuff.put(y);
					//			vertexBuff.put(z);
					TexCoord2f uv = new TexCoord2f();
					float u = uvnList.get();
					float v = uvnList.get();
					uv.x = u;
					uv.y = v;
					tempTexList.add(uv);
				}
				IntBuffer faceBuf = faces.get(p);
				for (int i = 0; i < faceBuf.array().length / 3; i++) {
					int p1 = faceBuf.get();
					int p2 = faceBuf.get();
					int p3 = faceBuf.get();
					tempCoordIdxList.add(p1);
					tempCoordIdxList.add(p2);
					tempCoordIdxList.add(p3);
					tempTexIdxList.add(p1);
					tempTexIdxList.add(p2);
					tempTexIdxList.add(p3);
				}
				this.parts.add(tempCoordList);
				this.parts.add(tempCoordIdxList);
				this.parts.add(tempNormList);
				this.parts.add(tempNormIdxList);
				this.parts.add(tempTexList);
				this.parts.add(tempTexIdxList);
			}
		}
		io.close();
	}

	private void loadIffModel0(BaseIffFile iff, N2k3DModelPart[] models) throws IOException {
		ByteFileReader io = new ByteFileReader(iff.getFile(), "r");
		for (int part = 0; part < models.length; part++) {
			N2k3DModelPart model = models[part];
			List tempCoordList = new ArrayList();
			List tempCoordIdxList = new ArrayList();
			List tempNormList = new ArrayList();
			List tempNormIdxList = new ArrayList();
			List tempTexList = new ArrayList();
			List tempTexIdxList = new ArrayList();
			int vertexNum = model.getVertexNum();
			int perSize = model.getPerVertexSize();
			//		vertexBuff = FloatBuffer.allocate(3 * vertexNum);
			//		normalBuff = FloatBuffer.allocate(3 * vertexNum);
			//		uvBuff = FloatBuffer.allocate(2 * vertexNum);
			ByteBuffer buffer = ByteBuffer.allocate(vertexNum * perSize);
			io.seek(model.getVertexDataStart());
			io.read(buffer.array());
			//System.out.println(buffer.capacity());
			for (int i = 0; i < vertexNum; i++) {
				Point3f vertex = new Point3f();
				float x = 0.0f;
				float y = 0.0f;
				float z = 0.0f;
				if (perSize == 8) {
					x = BufferUtil.readBytesAsShort(buffer, 2);
					y = BufferUtil.readBytesAsShort(buffer, 2);
					z = BufferUtil.readBytesAsShort(buffer, 2);
					float mod = BufferUtil.readBytesAsInt(buffer, 2);
					x = x / mod;
					y = y / mod;
					z = z / mod;
				} else {
					x = BufferUtil.readFloat(buffer);
					y = BufferUtil.readFloat(buffer);
					z = BufferUtil.readFloat(buffer);
				}
				vertex.x = x;
				vertex.y = y;
				vertex.z = z;
				tempCoordList.add(vertex);
				this.coordList.add(vertex);
				if (perSize > 12) {
					buffer.position(buffer.position() + (perSize - 12));
					continue;
				}
				//			vertexBuff.put(x);
				//			vertexBuff.put(y);
				//			vertexBuff.put(z);
				if (perSize == 100) {
					Vector3f normal = new Vector3f();
					x = BufferUtil.readFloat(buffer);
					y = BufferUtil.readFloat(buffer);
					z = BufferUtil.readFloat(buffer);
					normal.x = x;
					normal.y = y;
					normal.z = z;
					tempNormList.add(normal);
					//			normalBuff.put(x);
					//			normalBuff.put(y);
					//			normalBuff.put(z);
				}
				if (perSize == 100) {
					TexCoord2f uv = new TexCoord2f();
					float u = BufferUtil.readFloat(buffer);
					float v = BufferUtil.readFloat(buffer);
					uv.x = u;
					uv.y = v;
					tempTexList.add(uv);
					//			uvBuff.put(u);
					//			uvBuff.put(v);
				}
			}
			buffer.clear();
			io.seek(model.getFaceDataStart());
			int faceDataSize = model.getFaceDataSize();
			buffer = ByteBuffer.allocate(faceDataSize * 2);
			io.read(buffer.array());
			IntBuffer faceBuffer = N2kModelPartReader.decompressModelFaceDatas(buffer);
			faceBuffer.clear();
			int faceNum = faceBuffer.capacity() / 3;
			for (int i = 0; i < faceNum; i++) {
				int p1 = faceBuffer.get();
				int p2 = faceBuffer.get();
				int p3 = faceBuffer.get();
				tempCoordIdxList.add(p1);
				tempCoordIdxList.add(p2);
				tempCoordIdxList.add(p3);
				tempNormIdxList.add(p1);
				tempNormIdxList.add(p2);
				tempNormIdxList.add(p3);
				tempNormIdxList.add(p1);
				tempTexIdxList.add(p2);
				tempTexIdxList.add(p3);
				//			faceBuff.put(p1);
				//			faceBuff.put(p2);
				//			faceBuff.put(p3);
			}
			this.parts.add(tempCoordList);
			this.parts.add(tempCoordIdxList);
			this.parts.add(tempNormList);
			this.parts.add(tempNormIdxList);
			this.parts.add(tempTexList);
			this.parts.add(tempTexIdxList);
		}
		io.close();
	}

	private void readN2km(File n2kmFile) throws IOException {
		ByteFileReader io = new ByteFileReader(n2kmFile, "r");
		String desc = io.readBytesAsString(4);
		int vertexNum = io.read4BytesAsInt();
		int perSize = io.read4BytesAsInt();
		//		vertexBuff = FloatBuffer.allocate(3 * vertexNum);
		//		normalBuff = FloatBuffer.allocate(3 * vertexNum);
		//		uvBuff = FloatBuffer.allocate(2 * vertexNum);
		ByteBuffer buffer = ByteBuffer.allocate(vertexNum * 12);
		io.read(buffer.array());
		for (int i = 0; i < vertexNum; i++) {
			Point3f vertex = new Point3f();
			float x = BufferUtil.readFloat(buffer);
			float y = BufferUtil.readFloat(buffer);
			float z = BufferUtil.readFloat(buffer);
			vertex.x = x;
			vertex.y = y;
			vertex.z = z;
			this.coordList.add(vertex);
			//			vertexBuff.put(x);
			//			vertexBuff.put(y);
			//			vertexBuff.put(z);
			if (perSize >= 24) {
				Vector3f normal = new Vector3f();
				x = BufferUtil.readFloat(buffer);
				y = BufferUtil.readFloat(buffer);
				z = BufferUtil.readFloat(buffer);
				normal.x = x;
				normal.y = y;
				normal.z = z;
				this.normList.add(normal);
				//			normalBuff.put(x);
				//			normalBuff.put(y);
				//			normalBuff.put(z);
			} else {
				Vector3f normal = new Vector3f(0.5f, 0.5f, 0.5f);
				this.normList.add(normal);
				//			normalBuff.put(x);
				//			normalBuff.put(y);
				//			normalBuff.put(z);
			}
			if (perSize == 22 || perSize >= 32) {
				TexCoord2f uv = new TexCoord2f();
				float u = BufferUtil.readFloat(buffer);
				float v = BufferUtil.readFloat(buffer);
				uv.x = u;
				uv.y = v;
				this.texList.add(uv);
				//			uvBuff.put(u);
				//			uvBuff.put(v);
			}
		}

		int faceNum = io.read4BytesAsInt();
		buffer.clear();
		buffer = ByteBuffer.allocate(faceNum * 6);
		io.read(buffer.array());
		faceBuff = IntBuffer.allocate(faceNum * 3);
		for (int i = 0; i < faceNum; i++) {
			int p1 = BufferUtil.readBytesAsInt(buffer, 2);
			int p2 = BufferUtil.readBytesAsInt(buffer, 2);
			int p3 = BufferUtil.readBytesAsInt(buffer, 2);
			this.coordIdxList.add(p1);
			this.coordIdxList.add(p2);
			this.coordIdxList.add(p3);
			this.normIdxList.add(p1);
			this.normIdxList.add(p2);
			this.normIdxList.add(p3);
			this.texIdxList.add(p1);
			this.texIdxList.add(p2);
			this.texIdxList.add(p3);
			//			faceBuff.put(p1);
			//			faceBuff.put(p2);
			//			faceBuff.put(p3);
		}
		io.close();
	}

	private Point3f[] objectToPoint3Array(ArrayList inList) {
		Point3f outList[] = new Point3f[inList.size()];
		for (int i = 0; i < inList.size(); i++) {
			outList[i] = (Point3f) inList.get(i);
		}
		return outList;
	}

	private Vector3f[] objectToVectorArray(ArrayList inList) {
		Vector3f outList[] = new Vector3f[inList.size()];
		for (int i = 0; i < inList.size(); i++) {
			outList[i] = (Vector3f) inList.get(i);
		}
		return outList;
	}

	private TexCoord2f[] objectToTexCoord2Array(ArrayList inList) {
		TexCoord2f outList[] = new TexCoord2f[inList.size()];
		for (int i = 0; i < inList.size(); i++) {
			outList[i] = (TexCoord2f) inList.get(i);
		}
		return outList;
	}

	private int[] objectToIntArray(ArrayList inList) {
		int outList[] = new int[inList.size()];
		for (int i = 0; i < inList.size(); i++) {
			outList[i] = ((Integer) inList.get(i)).intValue();
		}
		return outList;
	}

	private BranchGroup createScene() {
		// Create Scene to pass back
		BranchGroup group = new BranchGroup();
		for (int p = 0; p < this.parts.size(); p += 6) {
			this.coordList = (ArrayList<Point3f>) parts.get(p);
			this.coordIdxList = (ArrayList<Integer>) parts.get(p + 1);
			this.normList = (ArrayList<Vector3f>) parts.get(p + 2);
			this.normIdxList = (ArrayList<Integer>) parts.get(p + 3);
			this.texList = (ArrayList<TexCoord2f>) parts.get(p + 4);
			this.texIdxList = (ArrayList<Integer>) parts.get(p + 5);
			int vertexCount = this.coordList.size() / 3;
			coordArray = objectToPoint3Array(coordList);
			Vector3f[] normals = null;
			if (normList.size() > 0) {
				normals = new Vector3f[vertexCount];
				normList.toArray(normals);
			}
			TexCoord2f[] textCoords = null;
			if (texList.size() > 0) {
				textCoords = new TexCoord2f[vertexCount];
				textCoords = texList.toArray(textCoords);
			}
			boolean gen_norms = normals == null || normals.length == 0;
			boolean do_tex = textCoords != null && textCoords.length > 0;
			if (!gen_norms) {
				normalArray = objectToVectorArray(normList);
			}
			if (do_tex) {
				textureArray = objectToTexCoord2Array(texList);
			}
			//convertToTriangles();

			if ((gen_norms) && (curSgroup != null)) {
				smoothingGroupNormals();
				gen_norms = false;
			}

			//create geometry info
			GeometryInfo gi = new GeometryInfo(GeometryInfo.TRIANGLE_ARRAY);
			//set vertex coordinate
			gi.setCoordinates(coordArray);
			IntBuffer indiceBuff = IntBuffer.allocate(this.coordIdxList.size());
			int faceNum = indiceBuff.capacity() / 3;
			for (int i = 0; i < faceNum; i++) {
				indiceBuff.put(((Integer) this.coordIdxList.get(i * 3 + 0)).intValue());
				indiceBuff.put(((Integer) this.coordIdxList.get(i * 3 + 1)).intValue());
				indiceBuff.put(((Integer) this.coordIdxList.get(i * 3 + 2)).intValue());
			}
			indiceBuff.rewind();
			gi.setCoordinateIndices(indiceBuff.array());

			//set texture coordinate
			indiceBuff.rewind();
			if (do_tex) {
				gi.setTextureCoordinateParams(1, 2);
				gi.setTextureCoordinateIndices(0, indiceBuff.array());
				gi.setTextureCoordinates(0, textCoords);
			} else {
				byte[] colors = new byte[vertexCount * 3];
				for (int i = 0; i < vertexCount; i++) {
					colors[i * 3 + 0] = (byte) 0xFF;
					colors[i * 3 + 0] = (byte) 0xAE;
					colors[i * 3 + 0] = (byte) 0x01;
				}
				gi.setColorIndices(indiceBuff.array());
				gi.setColors3(colors);
			}
			//generate normals must after set texture coordinates
			indiceBuff.rewind();
			if (gen_norms) {
				NormalGenerator normalGenerator = new NormalGenerator();
				normalGenerator.generateNormals(gi);
			} else {
				gi.setNormalIndices(indiceBuff.array());
				gi.setNormals(normals);
			}
			// Put geometry into Shape3d
			Shape3D shape = new Shape3D(gi.getGeometryArray(true, true, false));
			shape.setAppearance(appearance);

			//String matName = "default";
			//materials.assignMaterial(matName, shape);

			group.addChild(shape);
		}
		// 创建灯光,定向光源
		Color3f light1Color = new Color3f(1f, 1f, 1f);
		BoundingSphere bounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 1000.0);
		Vector3f light1Direction = new Vector3f(4.0f, -7.0f, -12.0f);
		DirectionalLight light1 = new DirectionalLight(light1Color, light1Direction);
		light1.setInfluencingBounds(bounds);
		group.addChild(light1);
		// 建立一个环境光源
		AmbientLight ambientLight = new AmbientLight(new Color3f(0.5f, 0.5f, 0.5f));
		group.addChild(ambientLight);
		return group;
	}

	private int[] groupIndices(ArrayList sourceList, ArrayList group) {
		int indices[] = new int[group.size() * 3];
		for (int i = 0; i < group.size(); i++) {
			int j = ((Integer) group.get(i)).intValue();
			indices[i * 3 + 0] = ((Integer) sourceList.get(j + 0)).intValue();
			indices[i * 3 + 1] = ((Integer) sourceList.get(j + 1)).intValue();
			indices[i * 3 + 2] = ((Integer) sourceList.get(j + 2)).intValue();
		}
		return indices;
	}

	private void smoothingGroupNormals() {
		NormalGenerator ng = new NormalGenerator(radians == -1.0f ? Math.PI : radians);
		NormalGenerator ng0 = new NormalGenerator(0.0);
		normList.clear();
		normIdxList = null;
		int newNormIdxArray[] = new int[coordIdxList.size()];

		Iterator e = triSgroups.keySet().iterator();
		while (e.hasNext()) {
			String curname = (String) e.next();
			ArrayList triList = (ArrayList) triSgroups.get(curname);

			// Check for group with no faces
			if (triList.size() > 0) {

				GeometryInfo gi = new GeometryInfo(GeometryInfo.TRIANGLE_ARRAY);

				gi.setCoordinateIndices(groupIndices(coordIdxList, triList));
				gi.setCoordinates(coordArray);

				if (curname.equals("0")) {
					ng0.generateNormals(gi);
				} else {
					ng.generateNormals(gi);
				}

				// Get the generated normals and indices
				Vector3f genNorms[] = gi.getNormals();
				int genNormIndices[] = gi.getNormalIndices();

				// Now we need to copy the generated normals into ObjectFile
				// data structures (normList and normIdxList).  The variable
				// normIdx is the index of the index of the normal currently
				// being put into the list.  It takes some calculation to
				// figure out the new index and where to put it.
				int normIdx = 0;
				// Repeat for each triangle in the smoothing group
				for (int i = 0; i < triList.size(); i++) {

					// Get the coordIdxList index of the first index in this face
					int idx = ((Integer) triList.get(i)).intValue();

					// Repeat for each vertex in the triangle
					for (int j = 0; j < 3; j++) {

						// Put the new normal's index into the index list
						newNormIdxArray[idx + j] = normList.size();

						// Add the vertex's normal to the normal list
						normList.add(genNorms[genNormIndices[normIdx++]]);
					}
				}
			}
		}
		normIdxList = new ArrayList(coordIdxList.size());
		for (int i = 0; i < coordIdxList.size(); i++) {
			normIdxList.add(new Integer(newNormIdxArray[i]));
		}
		normalArray = objectToVectorArray(normList);
	}

	private Point3f[] getLimits() {
		Point3f cur_vtx = new Point3f();

		// Find the limits of the model
		Point3f[] limit = new Point3f[2];
		limit[0] = new Point3f(Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE);
		limit[1] = new Point3f(Float.MIN_VALUE, Float.MIN_VALUE, Float.MIN_VALUE);
		for (int i = 0; i < coordList.size(); i++) {

			cur_vtx = (Point3f) coordList.get(i);

			// Keep track of limits for normalization
			if (cur_vtx.x < limit[0].x) {
				limit[0].x = cur_vtx.x;
			}
			if (cur_vtx.x > limit[1].x) {
				limit[1].x = cur_vtx.x;
			}
			if (cur_vtx.y < limit[0].y) {
				limit[0].y = cur_vtx.y;
			}
			if (cur_vtx.y > limit[1].y) {
				limit[1].y = cur_vtx.y;
			}
			if (cur_vtx.z < limit[0].z) {
				limit[0].z = cur_vtx.z;
			}
			if (cur_vtx.z > limit[1].z) {
				limit[1].z = cur_vtx.z;
			}
		}

		return limit;
	}

	/**
	 * Center the object and make it (-1,-1,-1) to (1,1,1).
	 */
	private void resize() {
		Point3f cur_vtx = new Point3f();
		float biggest_dif;

		Point3f[] limit = getLimits();

		// Move object so it's centered on (0,0,0)
		Vector3f offset = new Vector3f(-0.5f * (limit[0].x + limit[1].x), -0.5f * (limit[0].y + limit[1].y), -0.5f
				* (limit[0].z + limit[1].z));
		// Find the divide-by value for the normalization
		biggest_dif = limit[1].x - limit[0].x;
		if (biggest_dif < limit[1].y - limit[0].y) {
			biggest_dif = limit[1].y - limit[0].y;
		}
		if (biggest_dif < limit[1].z - limit[0].z) {
			biggest_dif = limit[1].z - limit[0].z;
		}
		biggest_dif /= 2.0f;

		for (int i = 0; i < coordList.size(); i++) {

			cur_vtx = (Point3f) coordList.get(i);

			cur_vtx.add(cur_vtx, offset);

			cur_vtx.x /= biggest_dif;
			cur_vtx.y /= biggest_dif;
			cur_vtx.z /= biggest_dif;

			// coordList.setElementAt(cur_vtx, i);
		}
	}

	class ModelInfo {

	}
}
